#include <stdio.h>
#include <tool/ylinkedList.h>
#include <tool/ysortedList.h>

/** Sorted list data struct */
struct sortedListData {
  /** use lined list */
  linkedList ll;
  /** Default <code>lesserFirst</code> is set to <code>true</code>. 
  If set to <code>true</code> sorting will place 
  item whose comparison value is lesser at the front. 
  Otherwise set to <code>false</code> sorting will place 
  item whose comparison value is greater at the front. */
  boolean lesserFirst;
  /*--- provide customized function pointers */
  /** This method is NOT provided, require customized function.
  This is NOT a compulsory function pointer. */
  void *(*itemClone)(const void *anItem, const void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doEqualAction)(sortedList list, 
      void *anItem, void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doEqualCloneAction)(sortedList list, 
      const void *anItem, void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddPrepareAction)(void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddPrepareCloneAction)(void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddBeforeSuccessAction)(void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddBeforeSuccessCloneAction)(void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddAfterSuccessAction)(void *aControlObj);
  /** Initialized with a dummy function, 
  override if customized function is provided. */
  boolean (*doAddAfterSuccessCloneAction)(void *aControlObj);
};

/*======= declare internal function */
boolean ysortedList_free(sortedList *listP);
boolean ysortedList_setLesserFirst(sortedList list, 
    const boolean lesserFirst);
g_reply ysortedList_isLesserFirst(const sortedList list);
int ysortedList_size(const sortedList list);
boolean ysortedList_clear(sortedList list);
/*--- traverse */
boolean ysortedList_current(const sortedList list);
boolean ysortedList_goNext(sortedList list);
boolean ysortedList_goBack(sortedList list);
boolean ysortedList_goFirst(sortedList list);
boolean ysortedList_goLast(sortedList list);
/*--- test */
boolean ysortedList_isEmpty(const sortedList list);
boolean ysortedList_isFirst(const sortedList list);
boolean ysortedList_isLast(const sortedList list);
boolean ysortedList_hasNext(const sortedList list);
boolean ysortedList_hasPrevious(const sortedList list);
/*--- item */
void *ysortedList_findItem(const sortedList list, const void *anItem);
void *ysortedList_findItemClone(const sortedList list, 
    const void *anItem, const void *aControlObj);
void *ysortedList_getItem(const sortedList list);
void *ysortedList_getItemClone(const sortedList list, 
    const void *aControlObj);
boolean ysortedList_deleteItem(sortedList list);
boolean ysortedList_deleteItemNOTFree(sortedList list);
boolean ysortedList_setItemNOTFree(sortedList list, void *anItem);
boolean ysortedList_addItem(sortedList list, 
    void *anItem, void *aControlObj);
boolean ysortedList_addItemClone(sortedList list, 
    const void *anItem, void *aControlObj);
boolean ysortedList_modifyItem(sortedList list, 
    void *anItem, void *aControlObj);
boolean ysortedList_modifyItemClone(sortedList list, 
    const void *anItem, void *aControlObj);
/*--- provide customized function */
boolean ysortedList_setFnItemClone(sortedList list, 
    void *(*itemClone)(const void *anItem, const void *aControlObj));
boolean ysortedList_setFnDoEqualAction(sortedList list, 
    boolean (*doEqualAction)(sortedList list, 
        void *anItem, void *aControlObj));
boolean ysortedList_setFnDoEqualCloneAction(sortedList list, 
    boolean (*doEqualCloneAction)(sortedList list, 
        const void *anItem, void *aControlObj));
boolean ysortedList_setFnDoAddPrepareAction(sortedList list, 
    boolean (*doAddPrepareAction)(void *aControlObj));
boolean ysortedList_setFnDoAddPrepareCloneAction(sortedList list, 
    boolean (*doAddPrepareCloneAction)(void *aControlObj));
boolean ysortedList_setFnDoAddBeforeSuccessAction(sortedList list, 
    boolean (*doAddBeforeSuccessAction)(void *aControlObj));
boolean ysortedList_setFnDoAddBeforeSuccessCloneAction(sortedList list, 
    boolean (*doAddBeforeSuccessCloneAction)(void *aControlObj));
boolean ysortedList_setFnDoAddAfterSuccessAction(sortedList list, 
    boolean (*doAddAfterSuccessAction)(void *aControlObj));
boolean ysortedList_setFnDoAddAfterSuccessCloneAction(sortedList list, 
    boolean (*doAddAfterSuccessCloneAction)(void *aControlObj));
/*--- function ONLY for internal use ---*/
boolean ysortedList_doEqualAction(sortedList list, 
    void *anItem, void *aControlObj);
boolean ysortedList_doEqualCloneAction(sortedList list, 
    const void *anItem, void *aControlObj);
boolean ysortedList_doAddPrepareAction(void *aControlObj);
boolean ysortedList_doAddPrepareCloneAction(void *aControlObj);
boolean ysortedList_doAddBeforeSuccessAction(void *aControlObj);
boolean ysortedList_doAddBeforeSuccessCloneAction(void *aControlObj);
boolean ysortedList_doAddAfterSuccessAction(void *aControlObj);
boolean ysortedList_doAddAfterSuccessCloneAction(void *aControlObj);

/*======= directly exposed function */
/** Create a new sortedList.
<p>MUST provide a function to free an item of type <code>void *</code>.
The function is of the form <code>boolean (*freeItem)(void **)</code>.
</p>
<p>MUST provide a function to compare two items of type <code>void *</code>.
The function is of the form 
<code>g_reply (*compareItem)(const void *, const void *)</code>.
</p>
<p>Default <code>lesserFirst</code> is set to <code>true</code>. 
If set to <code>true</code> sorting will place 
item whose comparison value is lesser at the front. 
Otherwise set to <code>false</code> sorting will place 
item whose comparison value is greater at the front. 
</p>
@param freeItem the function to free an item of type <code>void *</code>.
@param compareItem the function to compare two items of type <code>void *</code>.
@return a newly created and empty sortedList, 
  or <code>NULL</code> if failure.
*/
sortedList ysortedList_create(boolean (*freeItem)(void **anItemP),
    g_reply (*compareItem)(const void *anItem1, const void *anItem2)) {
  linkedList ll = ylinkedList_create(freeItem);
  if (ll == NULL) {return NULL;}
  /* compareItem */
  if (ll->setFnCompareItem(ll, compareItem) == false) {
    ll->free(&ll);
    return NULL;
  }
  sortedList list;
  FN_MALLOC_ERRMSG(list, sizeof(struct sortedList), 
      "Error: ysortedList_create(..) malloc(list)")
  if (list == NULL) {return NULL;}
  FN_MALLOC_ERRMSG(list->d, sizeof(struct sortedListData), 
      "Error: ysortedList_create(..) malloc(list->d)")
  if (list->d == NULL) {ysortedList_free(&list); return NULL;}
  /*--- data ---*/
  list->d->ll = ll;
  list->d->lesserFirst = true;
  list->d->itemClone = NULL;
  /* use dummy function */
  list->d->doEqualAction = ysortedList_doEqualAction;
  list->d->doEqualCloneAction = ysortedList_doEqualCloneAction;
  list->d->doAddPrepareAction = ysortedList_doAddPrepareAction;
  list->d->doAddPrepareCloneAction = 
      ysortedList_doAddPrepareCloneAction;
  list->d->doAddBeforeSuccessAction = 
      ysortedList_doAddBeforeSuccessAction;
  list->d->doAddBeforeSuccessCloneAction = 
      ysortedList_doAddBeforeSuccessCloneAction;
  list->d->doAddAfterSuccessAction = ysortedList_doAddAfterSuccessAction;
  list->d->doAddAfterSuccessCloneAction = 
      ysortedList_doAddAfterSuccessCloneAction;
  /*--- init function pointers ---*/
  list->free = ysortedList_free;
  list->setLesserFirst = ysortedList_setLesserFirst;
  list->isLesserFirst = ysortedList_isLesserFirst;
  list->size = ysortedList_size;
  list->clear = ysortedList_clear;
  /*--- traverse */
  list->current = ysortedList_current;
  list->goNext = ysortedList_goNext;
  list->goBack = ysortedList_goBack;
  list->goFirst = ysortedList_goFirst;
  list->goLast = ysortedList_goLast;
  /*--- test */
  list->isEmpty = ysortedList_isEmpty;
  list->isFirst = ysortedList_isFirst;
  list->isLast = ysortedList_isLast;
  list->hasNext = ysortedList_hasNext;
  list->hasPrevious = ysortedList_hasPrevious;
  /*--- item */
  list->findItem = ysortedList_findItem;
  list->findItemClone = ysortedList_findItemClone;
  list->getItem = ysortedList_getItem;
  list->getItemClone = ysortedList_getItemClone;
  list->deleteItem = ysortedList_deleteItem;
  list->deleteItemNOTFree = ysortedList_deleteItemNOTFree;
  list->setItemNOTFree = ysortedList_setItemNOTFree;
  list->addItem = ysortedList_addItem;
  list->addItemClone = ysortedList_addItemClone;
  list->modifyItem = ysortedList_modifyItem;
  list->modifyItemClone = ysortedList_modifyItemClone;
  /*--- provide customized function */
  list->setFnItemClone = ysortedList_setFnItemClone;
  list->setFnDoEqualAction = ysortedList_setFnDoEqualAction;
  list->setFnDoEqualCloneAction = ysortedList_setFnDoEqualCloneAction;
  list->setFnDoAddPrepareAction = ysortedList_setFnDoAddPrepareAction;
  list->setFnDoAddPrepareCloneAction = 
      ysortedList_setFnDoAddPrepareCloneAction;
  list->setFnDoAddBeforeSuccessAction = 
      ysortedList_setFnDoAddBeforeSuccessAction;
  list->setFnDoAddBeforeSuccessCloneAction = 
      ysortedList_setFnDoAddBeforeSuccessCloneAction;
  list->setFnDoAddAfterSuccessAction = 
      ysortedList_setFnDoAddAfterSuccessAction;
  list->setFnDoAddAfterSuccessCloneAction = 
      ysortedList_setFnDoAddAfterSuccessCloneAction;
  return list;
}

/** FUNCTION DISABLE DUE TO UNABLE TO PROVIDE NECESSARY 
customized function (above) BEFORE ITEM IS ADDED INTO THE SORT LIST.
Create a new sortedList with this item.
<p>MUST provide a function to free an item of type <code>void *</code>.
The function is of the form <code>boolean (*freeItem)(void **)</code>.
</p>
<p>MUST provide a function to compare two items of type <code>void *</code>.
The function is of the form 
<code>g_reply (*compareItem)(const void *, const void *)</code>.
</p>
@param anItem the item to be added.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@param freeItem the function to free an item of type <code>void *</code>.
@param itemClone the function to clone an item of type <code>void *</code>.
@return a newly created sortedList with item, 
  or <code>NULL</code> if failure.
sortedList ysortedList_createWithItem(void *anItem, void *aControlObj,
    boolean (*freeItem)(void **anItemP),
    g_reply (*compareItem)(const void *anItem1, const void *anItem2)) {
  sortedList list = ysortedList_create(freeItem, compareItem);
  if (list != NULL) {
    // do NOT bypass ysortedList_addItem(..) by calling 
    // list->d->ll->addItemAfter(list->d->ll, anItem);
    // there could be things to take care of in the control obj
    ysortedList_addItem(list, anItem, aControlObj);
  }
  return list;
}
*/

/** FUNCTION DISABLE DUE TO UNABLE TO PROVIDE NECESSARY 
customized function (above) BEFORE ITEM IS ADDED INTO THE SORT LIST.
Create a new sortedList with a clone of this item.
<p>MUST provide a function to free an item of type <code>void *</code>.
The function is of the form <code>boolean (*freeItem)(void **)</code>.
</p>
<p>MUST provide a function to compare two items of type <code>void *</code>.
The function is of the form 
<code>g_reply (*compareItem)(const void *, const void *)</code>.
</p>
<p>You are require to free the pass in item because 
it has not been added into the list. 
However its' cloned copy will be free by this list via the 
same function pointer call to <code>boolean (*freeItem)(void **)</code>,
this is because the cloned item's been added into the list.
</p>
@param anItem the item to be cloned and the clone will be added.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@param freeItem the function to free an item of type <code>void *</code>.
@param compareItem the function to compare two items of type <code>void *</code>.
@param itemClone the function to clone an item of type <code>void *</code>.
@return a newly created sortedList with item, 
  or <code>NULL</code> if failure.
sortedList ysortedList_createWithItemClone(void *anItem, void *aControlObj,
    boolean (*freeItem)(void **anItemP),
    g_reply (*compareItem)(const void *anItem1, const void *anItem2),
    void *(*itemClone)(const void *anItem, const void *aControlObj)) {
  if (itemClone == NULL) {return NULL;}
  sortedList list = ysortedList_create(freeItem, compareItem);
  if (list != NULL) {
    // set itemClone 
    if (ysortedList_setFnItemClone(list, itemClone) == false) {
      perror("Error: ysortedList_createWithItemClone(..) ysortedList_setFnItemClone(..) == false");
      ysortedList_free(&list);
      return NULL;
    }
    // clone 
    void *newItem = list->d->itemClone(anItem, aControlObj);
    if (newItem == NULL) {
      perror("Error: ysortedList_createWithItemClone(..) list->d->itemClone(anItem) == NULL");
      ysortedList_free(&list);
      return NULL;
    }
    // do NOT bypass ysortedList_addItem(..) by calling 
    // list->d->ll->addItemAfter(list->d->ll, newItem);
    // there could be things to take care of in the control obj
    ysortedList_addItemClone(list, newItem, aControlObj);
  }
  return list;
}
*/

/*======= exposed through function pointers */
/** Free this sorted List from memory.
@param listP pass in the address of sorted List struct pointer to be free.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_free(sortedList *listP) {
  /* NOT critical if list is NULL, assume all's fine */
  if (*listP == NULL) {return true;}
  if ((*listP)->d != NULL) {
    /* free sortedList */
    if ((*listP)->d->ll != NULL
      && (*listP)->d->ll->free(&(*listP)->d->ll) == false) {
      /* possible memory leak */
      perror("Error: ysortedList_free(sortedList *) (*listP)->d->ll->free(&(*listP)->d->ll)");
    }
    /* free the sortedListData struct */
    free((*listP)->d);
    (*listP)->d = NULL;
  }
  /* free the sortedList struct */
  free(*listP);
  *listP = NULL;
  return true;
}

/** Change <code>lesserFirst</code> value.
<p>Default <code>lesserFirst</code> is set to <code>true</code>. 
If set to <code>true</code> sorting will place 
item whose comparison value is lesser at the front. 
Otherwise set to <code>false</code> sorting will place 
item whose comparison value is greater at the front. 
</p>
@param list the sorted list.
@param lesserFirst to sort list by greater first set this to <code>false</code> 
  otherwise set to <code>true</code> to place lesser first.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setLesserFirst(sortedList list, 
    const boolean lesserFirst) {
  if (list == NULL || list->d == NULL) {return false;}
  list->d->lesserFirst = lesserFirst;
  return true;
}

/** Is list sort by lesser first?
Query <code>lesserFirst</code> value.
@param list the sorted list.
@return <code>g_replyYes</code> if value is <code>true</code>, 
  <code>g_replyNo</code> if value is <code>false</code>,
  or <code>g_replyFail</code> if failure occurs.
*/
g_reply ysortedList_isLesserFirst(const sortedList list) {
  if (list == NULL || list->d == NULL) {return g_replyFail;}
  if (list->d->lesserFirst == true) {
    return g_replyYes;
  } else {
    return g_replyNo;
  }
}

/** Returns the number of elements in this list.
@param list the sorted list.
@return Returns the number of elements in this list or -1 if failure.
*/
int ysortedList_size(const sortedList list) {
  if (list == NULL || list->d == NULL) {
    return -1;
  }
  return list->d->ll->size(list->d->ll);
}

/** Removes all of the elements from this list.
@param list the sorted list.
@return <code>true</code> if successful 
  otherwise <code>false</code> nothing to remove.
*/
boolean ysortedList_clear(sortedList list) {
  if (list == NULL || list->d == NULL) {
    return false;
  }
  return list->d->ll->clear(list->d->ll);
}

/*--- traverse */
/** If the list currently point at something.
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_current(const sortedList list) {
  /* currently must point to something */
  if (list == NULL || list->d == NULL) {return false;}
  return list->d->ll->current(list->d->ll);
}

/** Move to next item. Successful if next in list point at something, 
otherwise stay at the tail of the list.
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_goNext(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->goNext(list->d->ll);
  } else {
    return list->d->ll->goBack(list->d->ll);
  }
}

/** Move back a item. Successful if previous in list point at something, 
otherwise stay at the head of the list.
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_goBack(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->goBack(list->d->ll);
  } else {
    return list->d->ll->goNext(list->d->ll);
  }
}

/** Move to the first item in the list. 
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_goFirst(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->goFirst(list->d->ll);
  } else {
    return list->d->ll->goLast(list->d->ll);
  }
}

/** Move to the last item in the list. 
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_goLast(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->goLast(list->d->ll);
  } else {
    return list->d->ll->goFirst(list->d->ll);
  }
}

/*--- test */
/** Tests if this list has no elements.
@param list the sorted list.
@return <code>true</code> if successful otherwise <code>false</code>.
*/
boolean ysortedList_isEmpty(const sortedList list) {
  /* currently must point to something */
  if (list == NULL || list->d == NULL) {return true;}
  return list->d->ll->isEmpty(list->d->ll);
}

/** Are we currently pointing to the first item in the list?
@param list the sorted list.
@return true if pointing to the first item, false otherwise.
*/
boolean ysortedList_isFirst(const sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->isFirst(list->d->ll);
  } else {
    return list->d->ll->isLast(list->d->ll);
  }
}

/** Are we currently pointing to the last item in the list?
@param list the sorted list.
@return true if pointing to the last item, false otherwise.
*/
boolean ysortedList_isLast(const sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->isLast(list->d->ll);
  } else {
    return list->d->ll->isFirst(list->d->ll);
  }
}

/** Is there another item after current item in the list?
@param list the sorted list.
@return true if successful, false otherwise.
*/
boolean ysortedList_hasNext(const sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->hasNext(list->d->ll);
  } else {
    return list->d->ll->hasPrevious(list->d->ll);
  }
}

/** Is there another item before current item in the list?
@param list the sorted list.
@return true if successful, false otherwise.
*/
boolean ysortedList_hasPrevious(const sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  if (list->d->lesserFirst == true) {
    return list->d->ll->hasPrevious(list->d->ll);
  } else {
    return list->d->ll->hasNext(list->d->ll);
  }
}

/*--- item */
/** Find this item (with certain attribute, e.g. with this key) 
from the list and return the one from the list.
Use <code>g_reply (*compareItem)(const void *, const void *)</code> as
a way to compare the items.
@param list the sorted list.
@param anItem the item to compare against those in the list.
@return Return the found item, 
  <code>NULL</code> if not found or failure occurs.
*/
void *ysortedList_findItem(const sortedList list, const void *anItem) {
  if (list == NULL || list->d == NULL || anItem == NULL) {
    perror("Error: ysortedList_findItem(..) .. == NULL");
    return NULL;
  }
  /* if currently point to something */
  if (list->d->ll->current(list->d->ll)) {
    /* mark current position */
    list->d->ll->mark(list->d->ll);
    boolean doLoop = false;
    g_reply compare, comparePrev;
    comparePrev = g_replyEqual;
    do {
      compare = list->d->ll->compareItem(list->d->ll, anItem);
      if (compare == g_replyLesser) {
        if (comparePrev == g_replyLesser || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goBack(list->d->ll);
        } else { /* item NOT found */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyGreater) {
        if (comparePrev == g_replyGreater || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goNext(list->d->ll);
        } else { /* item NOT found */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyFail) { /* failure in function */
        perror("Error: ysortedList_findItem(..) list->d->ll->compareItem(..) == g_replyFail");
        return NULL;
      } else { /* found existing & exact key */
        return list->d->ll->getItem(list->d->ll);
      }
    } while (doLoop);
    /* restore mark position */
    list->d->ll->goMark(list->d->ll);
  } /* else assume an empty new list */
  return NULL;
}

/** Find this item (with certain attribute, e.g. with this key) 
from the list and return a clone of the one from the list.
Use <code>g_reply (*compareItem)(const void *, const void *)</code> as
a way to compare the items.
@param list the sorted list.
@param anItem the item to compare against those in the list.
@return Return a clone of the found item, 
  <code>NULL</code> if not found or failure occurs.
*/
void *ysortedList_findItemClone(const sortedList list, 
    const void *anItem, const void *aControlObj) {
  if (list == NULL || list->d == NULL || anItem == NULL) {
    perror("Error: ysortedList_findItemClone(..) .. == NULL");
    return NULL;
  }
  /* if currently point to something */
  if (list->d->ll->current(list->d->ll)) {
    /* mark current position */
    list->d->ll->mark(list->d->ll);
    boolean doLoop = false;
    g_reply compare, comparePrev;
    comparePrev = g_replyEqual;
    do {
      compare = list->d->ll->compareItem(list->d->ll, anItem);
      if (compare == g_replyLesser) {
        if (comparePrev == g_replyLesser || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goBack(list->d->ll);
        } else { /* item NOT found */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyGreater) {
        if (comparePrev == g_replyGreater || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goNext(list->d->ll);
        } else { /* item NOT found */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyFail) { /* failure in function */
        perror("Error: ysortedList_findItemClone(..) list->d->ll->compareItem(..) == g_replyFail");
        return NULL;
      } else { /* found existing & exact key */
        return list->d->ll->getItemClone(list->d->ll, aControlObj);
      }
    } while (doLoop);
    /* restore mark position */
    list->d->ll->goMark(list->d->ll);
  } /* else assume an empty new list */
  return NULL;
}

/** Obtain the item currently pointing to in the list. 
<p>WARNING: Do not change the item, or the list and its' sorting 
will NOT work properly!
This is provided for better speed. If speed is NOT a concern then recommend 
to use <code>getItemClone(..)</code> instead, to minimise possible 
modification to list item. If modification is required use 
<code>modifyItem(..)</code> or <code>modifyItemClone(..)</code> function.
</p>
@param list the sorted list.
@return a "cloned" copy of the item currently pointing to in the list, or
  <code>NULL</code> if failure.
*/
void *ysortedList_getItem(const sortedList list) {
  if (list == NULL || list->d == NULL) {return NULL;}
  return list->d->ll->getItem(list->d->ll);
}

/** Obtain a "cloned" copy of the item currently pointing to in the list. 
<p>You SHOULD free this "cloned" copy of the item cloned from the list.
The list does NOT keep track of these "clones" and shouldn't release them..
<br/>UNLESS the item does some trick to <b>keep track of it's own clone</b>, 
AND also release them via the same function pointer call to 
<code>boolean (*freeItem)(void **)</code>.
<br/><b>Advice:</b> Read the item's library for details.
</p>
@param list the sorted list.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return a "cloned" copy of the item currently pointing to in the list, or
  <code>NULL</code> if failure.
*/
void *ysortedList_getItemClone(const sortedList list, 
    const void *aControlObj) {
  if (list == NULL || list->d == NULL) {return NULL;}
  return list->d->ll->getItemClone(list->d->ll, aControlObj);
}

/** Delete the current item from the list. 
After deletion the new current item will become the next item if it exist, 
otherwise the new current item will become the item in front if it exist.
If no item exist in front or to the back, the list is empty, 
current has no item and points to <code>NULL</code>.
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_deleteItem(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  return list->d->ll->deleteItem(list->d->ll);
}

/** Delete the current item from the list 
BUT will NOT free the deleted item from memory!
After deletion the new current item will become the next item if it exist, 
otherwise the new current item will become the item in front if it exist.
If no item exist in front or to the back, the list is empty, 
current has no item and points to <code>NULL</code>.
@param list the sorted list.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_deleteItemNOTFree(sortedList list) {
  if (list == NULL || list->d == NULL) {return false;}
  return list->d->ll->deleteItemNOTFree(list->d->ll);
}

/** Set a new item over the current item in the list, 
BUT will NOT free the previous item from memory!
Note this is NOT adding.
@param list the sorted list.
@param anItem the item to be added.
@param aControlObj an object that customized function may work with,
  e.g. increasing some specific counter or doing other duty 
  when a specific action has occurred.
@return <code>true</code> if successfully, 
  or <code>false</code> if failure occurs.
*/
boolean ysortedList_setItemNOTFree(sortedList list, void *anItem) {
  if (list == NULL || list->d == NULL) {return false;}
  return list->d->ll->setItemNOTFree(list->d->ll, anItem);
}

/** Add the item into the list, according to the sorting order.
NB: item is allow to be <code>NULL</code>.
<p>If the item already exist, control is pass to customized function 
<code>doEqualAction(..)</code> to handle the situation.
If the item is new, a prepare add event customized function 
<code>doAddPrepareAction(..)</code> will be called.
</p>
<p>After this item is added,
if add is successful, specific customized function after the event 
add item before current <code>doAddBeforeSuccessAction(..)</code>
or add item after current <code>doAddAfterSuccessAction(..)</code> 
will be called.
</p>
@param list the sorted list.
@param anItem the item to be added.
@param aControlObj an object that customized function may work with,
  e.g. increasing some specific counter or doing other duty 
  when a specific action has occurred.
@return <code>true</code> if successfully, 
  or <code>false</code> if failure occurs.
*/
boolean ysortedList_addItem(sortedList list, void *anItem, 
    void *aControlObj) {
  if (list == NULL || list->d == NULL) {
    perror("Error: ysortedList_addItem(..) .. == NULL");
    return false;
  }
  boolean addAfter = true;
  /* if currently point to something */
  if (list->d->ll->current(list->d->ll)) {
    boolean doLoop = false;
    g_reply compare, comparePrev;
    comparePrev = g_replyEqual;
    do {
      compare = list->d->ll->compareItem(list->d->ll, anItem);
      /** will place the lesser compare in front of the list **/
      if (compare == g_replyLesser) {
        addAfter = false;
        if (comparePrev == g_replyLesser || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goBack(list->d->ll);
        } else { /* found place to add, new key */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyGreater) {
        addAfter = true;
        if (comparePrev == g_replyGreater || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goNext(list->d->ll);
        } else { /* found place to add, new key */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyFail) { /* failure in function */
        perror("Error: ysortedList_addItem(..) list->d->ll->compareItem(..) == g_replyFail");
        return false;
      } else { /* found existing & exact key */
        /* do equal action */
        if (list->d->doEqualAction(list, anItem, aControlObj) == false) {
          perror("Error: ysortedList_addItem(..) list->d->doEqualAction(..) == false");
          return false;
        }
        return true;
      }
    } while (doLoop);
  } /* else assume an empty new list: so just add. */

  /* prepare */
  if (list->d->doAddPrepareAction(aControlObj) == false) {
    perror("Error: ysortedList_addItem(..) list->d->doAddPrepareAction(..) == false");
    return false;
  }
  /* add */
  if (addAfter) {
    if (list->d->ll->addItemAfter(list->d->ll, anItem) == false) {
      /* unable to add the item */
      perror("Error: ysortedList_addItem(..) list->d->ll->addItemAfter(..) == false");
      return false;
    }
    /* do add after action */
    if (list->d->doAddAfterSuccessAction(aControlObj) == false) {
      perror("Error: ysortedList_addItem(..) list->d->doAddAfterSuccessAction(..) == false");
      return false;
    }
  } else {
    if (list->d->ll->addItemBefore(list->d->ll, anItem) == false) {
      /* unable to add the item */
      perror("Error: ysortedList_addItem(..) list->d->ll->addItemBefore(..) == false");
      return false;
    }
    /* do add before action */
    if (list->d->doAddBeforeSuccessAction(aControlObj) == false) {
      perror("Error: ysortedList_addItem(..) list->d->doAddBeforeSuccessAction(..) == false");
      return false;
    }
  }
  return true;
}

/** Add the item into the list, according to the sorting order.
NB: item is allow to be <code>NULL</code>.
<p>If the item already exist, control is pass to customized function 
<code>doEqualCloneAction(..)</code> to handle the situation.
If the item is new, a prepare add event customized function 
<code>setFnDoAddPrepareCloneAction(..)</code> will be called.
</p>
<p>Then the item will be cloned and then added into the list.
After this cloned item is added,
if add is successful, specific customized function after the event 
add item before current <code>doAddBeforeSuccessCloneAction(..)</code>
or add item after current <code>doAddAfterSuccessCloneAction(..)</code> 
will be called.
</p>
<p>You are require to free the pass in item because 
it has not been added into the list. 
However its' cloned copy will be free by this list via the 
same function pointer call to <code>boolean (*freeItem)(void **)</code>,
this is because the cloned item's been added into the list.
</p>
@param list the sorted list.
@param anItem the item to be cloned and the clone will be added.
@param aControlObj an object that customized function may work with,
  e.g. increasing some specific counter or doing other duty 
  when a specific action has occurred.
@return <code>true</code> if successfully, 
  or <code>false</code> if failure occurs.
*/
boolean ysortedList_addItemClone(sortedList list, const void *anItem, 
    void *aControlObj) {
  if (list == NULL || list->d == NULL || list->d->itemClone == NULL) {
    perror("Error: ysortedList_addItemClone(..) .. == NULL");
    return false;
  }
  boolean addAfter = true;
  /* if currently point to something */
  if (list->d->ll->current(list->d->ll)) {
    boolean doLoop = false;
    g_reply compare, comparePrev;
    comparePrev = g_replyEqual;
    do {
      compare = list->d->ll->compareItem(list->d->ll, anItem);
      /** will place the lesser compare in front of the list **/
      if (compare == g_replyLesser) {
        addAfter = false;
        if (comparePrev == g_replyLesser || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goBack(list->d->ll);
        } else { /* found place to add, new key */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyGreater) {
        addAfter = true;
        if (comparePrev == g_replyGreater || comparePrev == g_replyEqual) { 
          /* at start comparePrev is g_replyEqual */
          comparePrev = compare;
          doLoop = list->d->ll->goNext(list->d->ll);
        } else { /* found place to add, new key */
          doLoop = false; /* in case code change! */
          break;
        }
      } else if (compare == g_replyFail) { /* failure in function */
        perror("Error: ysortedList_addItemClone(..) list->d->ll->compareItem(..) == g_replyFail");
        return false;
      } else { /* found existing & exact key */
        /* do equal action */
        if (list->d->doEqualCloneAction(list, anItem, aControlObj) == false) {
          perror("Error: ysortedList_addItemClone(..) list->d->doEqualCloneAction(..) == false");
          return false;
        }
        return true;
      }
    } while (doLoop);
  } /* else assume an empty new list: so just add. */

  /* prepare */
  if (list->d->doAddPrepareCloneAction(aControlObj) == false) {
    perror("Error: ysortedList_addItemClone(..) list->d->doAddPrepareCloneAction(..) == false");
    return false;
  }
  /* clone */
  void *newItem = list->d->itemClone(anItem, aControlObj);
  if (newItem == NULL) {
    perror("Error: ysortedList_addItemClone(..) list->d->itemClone(anItem, aControlObj) == NULL");
    return false;
  }
  /* add */
  if (addAfter) {
    if (list->d->ll->addItemAfter(list->d->ll, newItem) == false) {
      /* unable to add the item */
      perror("Error: ysortedList_addItemClone(..) list->d->ll->addItemAfter(..) == false");
      return false;
    }
    /* do add after action */
    if (list->d->doAddAfterSuccessCloneAction(aControlObj) == false) {
      perror("Error: ysortedList_addItemClone(..) list->d->doAddAfterSuccessCloneAction(..) == false");
      return false;
    }
  } else {
    if (list->d->ll->addItemBefore(list->d->ll, newItem) == false) {
      /* unable to add the item */
      perror("Error: ysortedList_addItemClone(..) list->d->ll->addItemBefore(..) == false");
      return false;
    }
    /* do add before action */
    if (list->d->doAddBeforeSuccessCloneAction(aControlObj) == false) {
      perror("Error: ysortedList_addItemClone(..) list->d->doAddBeforeSuccessCloneAction(..) == false");
      return false;
    }
  }
  return true;
}

/** Modify current item with this new item.
This function is equivalent to calling <code>deleteItem(..)</code>
then <code>addItem(..)</code>.
@param list the sorted list.
@param anItem the item to be added.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_modifyItem(sortedList list, 
    void *anItem, void *aControlObj) {
  if (ysortedList_deleteItem(list) == false) {return false;}
  return ysortedList_addItem(list, anItem, aControlObj);
}

/** Modify current item with a clone of this new item, 
i.e. do not add this new item in directly but use a clone of it.
This function is equivalent to calling <code>deleteItem(..)</code>
then <code>addItemClone(..)</code>.
<p>You are require to free the pass in item because 
it has not been added into the list. 
However its' cloned copy will be free by this list via the 
same function pointer call to <code>boolean (*freeItem)(void **)</code>,
this is because the cloned item's been added into the list.
</p>
@param list the sorted list.
@param anItem the item to be added.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_modifyItemClone(sortedList list, 
    const void *anItem, void *aControlObj) {
  if (ysortedList_deleteItem(list) == false) {return false;}
  return ysortedList_addItemClone(list, anItem, aControlObj);
}

/*--- provide customized function */
/** Provide a function to clone an item of type <code>void *</code>.
The function is of the form 
<code>void *(*itemClone)(const void *, const void *)</code>.
<p>This is a customized function provided by the item's library 
and is NOT compulsory.
</p>
<p>WARNING: Anything that is added into the list, cloned or NOT cloned will
be free by this list. Know what you're doing, use the right function 
for the work, those that provide cloning ability 
and/or NO cloning ability.
</p>
@param list the sorted list.
@param itemClone the function to clone an item of type <code>void *</code>.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnItemClone(sortedList list, 
    void *(*itemClone)(const void *anItem, const void *aControlObj)) {
  if (list == NULL || list->d == NULL || itemClone == NULL) {
    return false;
  }
  list->d->itemClone = itemClone;
  return list->d->ll->setFnItemClone(list->d->ll, itemClone);
}

/** Provide a "do equal action" customized function 
for <code>addItem(..)</code>, the function will be called when 
<code>compareItem</code> return a <code>g_replyEqual</code>, 
i.e. item already exist within the list, customized function 
<code>doEqualAction</code> will handle this situation.
The function is of the form 
<code>boolean (*doEqualAction)(sortedList, void *, void *)</code>.
@param list the sorted list.
@param doEqualAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoEqualAction(sortedList list, 
    boolean (*doEqualAction)(sortedList list, 
        void *anItem, void *aControlObj)) {
  if (list == NULL || list->d == NULL || doEqualAction == NULL) {
    return false;
  }
  list->d->doEqualAction = doEqualAction;
  return true;
}

/** Provide a "do equal clone action" customized function 
for <code>addItemClone(..)</code>, the function will be called when 
<code>compareItem</code> return a <code>g_replyEqual</code>, 
i.e. item already exist within the list, customized function 
<code>doEqualCloneAction</code> will handle this situation.
The function is of the form 
<code>boolean (*doEqualCloneAction)(sortedList, void *, void *)</code>.
@param list the sorted list.
@param doEqualCloneAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoEqualCloneAction(sortedList list, 
    boolean (*doEqualCloneAction)(sortedList list, 
        const void *anItem, void *aControlObj)) {
  if (list == NULL || list->d == NULL || doEqualCloneAction == NULL) {
    return false;
  }
  list->d->doEqualCloneAction = doEqualCloneAction;
  return true;
}

/** Provide a "do add prepare action" customized function 
for <code>addItem(..)</code>, the function will be called before 
adding the item into list e.g. <code>aControlObj</code> 
could perform specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddPrepareAction)(void *)</code>.
@param list the sorted list.
@param doAddPrepareAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddPrepareAction(sortedList list, 
    boolean (*doAddPrepareAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL || doAddPrepareAction == NULL) {
    return false;
  }
  list->d->doAddPrepareAction = doAddPrepareAction;
  return true;
}

/** Provide a "do add prepare action" customized function 
for <code>addItemClone(..)</code>, the function will be called before 
adding the cloned item into list e.g. <code>aControlObj</code> 
could perform specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddPrepareCloneAction)(void *)</code>.
@param list the sorted list.
@param doAddPrepareCloneAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddPrepareCloneAction(sortedList list, 
    boolean (*doAddPrepareCloneAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL || doAddPrepareCloneAction == NULL) {
    return false;
  }
  list->d->doAddPrepareCloneAction = doAddPrepareCloneAction;
  return true;
}

/** Provide a "do add before success action" customized function 
for <code>addItem(..)</code>, the function will be called AFTER 
the event of successfully adding an item before the current pointer 
in the list e.g. <code>aControlObj</code> could perform 
specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddBeforeSuccessAction)(void *)</code>.
@param list the sorted list.
@param doAddBeforeSuccessAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddBeforeSuccessAction(sortedList list, 
    boolean (*doAddBeforeSuccessAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL 
      || doAddBeforeSuccessAction == NULL) {
    return false;
  }
  list->d->doAddBeforeSuccessAction = doAddBeforeSuccessAction;
  return true;
}

/** Provide a "do add before success action" customized function 
for <code>addItemClone(..)</code>, the function will be called AFTER 
the event of successfully adding a cloned item before the current pointer 
in the list e.g. <code>aControlObj</code> could perform 
specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddBeforeSuccessCloneAction)(void *)</code>.
@param list the sorted list.
@param doAddBeforeSuccessCloneAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddBeforeSuccessCloneAction(sortedList list, 
    boolean (*doAddBeforeSuccessCloneAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL 
      || doAddBeforeSuccessCloneAction == NULL) {
    return false;
  }
  list->d->doAddBeforeSuccessCloneAction = doAddBeforeSuccessCloneAction;
  return true;
}

/** Provide a "do add after success action" customized function 
for <code>addItem(..)</code>, the function will be called AFTER 
the event of successfully adding an item after the current pointer 
in the list e.g. <code>aControlObj</code> could perform 
specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddAfterSuccessAction)(void *)</code>.
@param list the sorted list.
@param doAddAfterSuccessAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddAfterSuccessAction(sortedList list, 
    boolean (*doAddAfterSuccessAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL 
      || doAddAfterSuccessAction == NULL) {
    return false;
  }
  list->d->doAddAfterSuccessAction = doAddAfterSuccessAction;
  return true;
}

/** Provide a "do add after success action" customized function 
for <code>addItemClone(..)</code>, the function will be called AFTER 
the event of successfully adding a cloned item after the current pointer 
in the list e.g. <code>aControlObj</code> could perform 
specialized counting and other duties.
The function is of the form 
<code>boolean (*doAddAfterSuccessCloneAction)(void *)</code>.
@param list the sorted list.
@param doAddAfterSuccessCloneAction the customized function.
@return <code>true</code> if successfully otherwise <code>false</code>.
*/
boolean ysortedList_setFnDoAddAfterSuccessCloneAction(sortedList list, 
    boolean (*doAddAfterSuccessCloneAction)(void *aControlObj)) {
  if (list == NULL || list->d == NULL 
      || doAddAfterSuccessCloneAction == NULL) {
    return false;
  }
  list->d->doAddAfterSuccessCloneAction = doAddAfterSuccessCloneAction;
  return true;
}

/*======= function ONLY for internal use */
/** A dummpy function for <code>ysortedList_addItem(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param list the sorted list.
@param anItem the item to work with.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doEqualAction(sortedList list, 
    void *anItem, void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItemClone(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param list the sorted list.
@param anItem the item to work with.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doEqualCloneAction(sortedList list, 
    const void *anItem, void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItem(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddPrepareAction(void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItemClone(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddPrepareCloneAction(void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItem(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddBeforeSuccessAction(void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItemClone(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddBeforeSuccessCloneAction(void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItem(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddAfterSuccessAction(void *aControlObj) {
  return true;
}

/** A dummpy function for <code>ysortedList_addItemClone(..)</code>.
This function is for internal use ONLY, do NOT expose this.
@param aControlObj an object that customized function may work with,
  e.g. provide cloning ability, other facility and perform other duty.
@return always return true.
*/
boolean ysortedList_doAddAfterSuccessCloneAction(void *aControlObj) {
  return true;
}
